# -*- coding: utf-8 -*-

__authur__ = 'Yu XH'

import copy
import random
from myAI.hexmap.handle_map import *


class RedOprs:
    class TuJiDui_1:
        Tank, IFV, Infantry, UCV, CM_0, CM_1 = 0, 100, 200, 400, 700, 701
        # 初始位置：Tank: 1832, IFV: 1732, Infantry: 1732, UCV: 1732, CM_0: 1732, CM_1: 1732

    class TuJiDui_2:
        Tank, IFV, Infantry, UCV, CM_0, CM_1 = 1000, 1100, 1200, 1400, 1700, 1701
        # 初始位置：Tank: 2139, IFV: 2039, Infantry: 2039, UCV: 2039, CM_0: 2039, CM_1: 2039

    class TuJiDui_3:
        Tank, IFV, Infantry, UCV, CM_0, CM_1 = 2000, 2100, 2200, 2400, 2700, 2701
        # 初始位置：Tank: 2349, IFV: 2348, Infantry: 2348, UCV: 2348, CM_0: 2348, CM_1: 2348

    class TuJiDui_4:
        Tank, IFV, Infantry, UCV, CM_0, CM_1 = 3000, 3100, 3200, 3400, 3700, 3701
        # 初始位置：Tank: 1953, IFV: 1853, Infantry: 1853, UCV: 1853, CM_0: 1853, CM_1: 1853

    class ZhiShengJi:
        Helicopter_0, Helicopter_1 = 4600, 4601
        # 初始位置：Helicopter_0: 838, Helicopter_1: 1137

    class WuRenJi:
        Drone_0, Drone_1 = 4500, 4501
        # 初始位置：Drone_0: 839, Drone_1: 1138

    class PaoBingQun:
        Artillery_0, Artillery_1, Artillery_2, Artillery_3, Artillery_4, Artillery_5 = 5300, 5301, 5302, 5303, 5304, 5305
        # 初始位置：Artillery_0: 937, Artillery_1: 938, Artillery_2: 939, Artillery_3: 1037, Artillery_4: 1038, Artillery_5: 1039


class BlueOprs:
    class XianQianDui_1:
        Tank_0, Tank_1, IFV_0, IFV_1, Infantry_0, Infantry_1 = 10000, 10001, 10100, 10101, 10200, 10201
        # 初始位置：Tank_0: 6338, Tank_1: 6338, IFV_0: 6337, IFV_1: 6438, Infantry_0: 6337, Infantry_1: 6438

    class XianQianDui_2:
        Tank_0, Tank_1, IFV_0, IFV_1, Infantry_0, Infantry_1 = 11000, 11001, 11100, 11101, 11200, 11201
        # 初始位置：Tank_0: 6446, Tank_1: 6446, IFV_0: 6546, IFV_1: 6647, Infantry_0: 6546, Infantry_1: 6647

    class XianQianDui_3:
        Tank_0, Tank_1, IFV_0, IFV_1, Infantry_0, Infantry_1 = 12000, 12001, 12100, 12101, 12200, 12201
        # 初始位置：Tank_0: 5451, Tank_1: 5451, IFV_0: 5551, IFV_1: 5652, Infantry_0: 5551, Infantry_1: 5652

    class XianQianDui_4:
        Tank_0, Tank_1, IFV_0, IFV_1, Infantry_0, Infantry_1 = 13000, 13001, 13100, 13101, 13200, 13201
        # 初始位置：Tank_0: 5455, Tank_1: 5455, IFV_0: 5555, IFV_1: 5656, Infantry_0: 5555, Infantry_1: 5656

    class ZhiShengJi:
        Helicopter_0, Helicopter_1 = 14600, 14601
        # 初始位置：Helicopter_0: 7337, Helicopter_1: 7637

    class WuRenJi:
        Drone_0, Drone_1 = 14500, 14501
        # 初始位置：Drone_0: 7338, Drone_1: 7638

    class PaoBingQun:
        Artillery_0, Artillery_1, Artillery_2, Artillery_3, Artillery_4, Artillery_5 = 15300, 15301, 15302, 15303, 15304, 15305
        # 初始位置：Artillery_0: 7437, Artillery_1: 7438, Artillery_2: 7439, Artillery_3: 7536, Artillery_4: 7537, Artillery_5: 7538


class FactionAIBlue:
    """蓝方AI"""

    def __init__(self, myAgent):
        self.color = myAgent.color
        self.scenario = myAgent.scenario
        self.max_step = 2880
        self.tactic = []  # 我方策略，'1-attack' | '2-defend'
        self.group_info = {}  # 保存动态分组信息 {group_name: {group_task: ['ToOccupy', city], obj_ids: [opr1, opr2]}}
        self.group_static = {}  # 保存静态分组信息，用于分组动态变化后的回归
        self.init_groups()  # 初始化算子分组，分组结果整场比赛不变化
        self.task = {}  # 与是factionAI的副本，保存算子分配的任务信息{obj_id:['outputfire',param1,param2]}
        self.task_backup = {}  # 用于临时备份某些任务，方便调度
        self.last_observation = myAgent.scenario_info[-1]  # 保存上一步状态，便于和当前状态比较
        self.tan_ke = TanKe(self)
        self.bu_bing = BuBing(self)
        self.zhan_che = ZhanChe(self)
        self.pao_bing = PaoBing(self)
        self.zhi_sheng_ji = ZhiShengJi(self)
        self.wu_ren_ji = WuRenJi(self)

    def update(self, factionAI, myAgent):
        myAgent.agenda.ipcArgs.mutex_task.acquire()
        self.task = copy.deepcopy(factionAI.task)
        myAgent.agenda.ipcArgs.mutex_task.release()

        our_oprs = myAgent.get_our_oprs()

        # 没有可以使用的算子
        if not our_oprs:
            self.task = {}
            return

        # 如果我方有算子死亡，则将其任务删除
        our_oprs_id = [opr['obj_id'] for opr in our_oprs]
        need_pop = [opr_id for opr_id in self.task.keys() if opr_id not in our_oprs_id]
        for pop_id in need_pop:
            self.task.pop(pop_id)

        # 如果我方算子有无效任务（Success, Failure, Error等），将任务删除
        for opr in our_oprs:
            opr_id = opr['obj_id']
            if opr_id in self.task.keys():
                if self.task[opr_id][0] in ['Success', 'Failure', 'Error']:
                    self.task.pop(opr_id)

        # 将死亡算子的信息从group_info中移除
        self.remove_group_dead_members(myAgent)

        # 对我方算子进行重分组 -- 分组策略
        self.regroup_oprs(myAgent)

        # 分组任务分派
        self.zhan_che.plan(self, myAgent)
        self.bu_bing.plan(self, myAgent)
        self.tan_ke.plan(self, myAgent)
        self.zhi_sheng_ji.plan(self, myAgent)
        self.wu_ren_ji.plan(self, myAgent)
        self.pao_bing.plan(self, myAgent)

        # 跨组分派任务
        self.make_tactic(myAgent)
        if 'CleanCities_1' in self.tactic:
            self.plan_clean_cities_1(myAgent)
        elif 'SearchVehicle' in self.tactic:
            self.plan_search_vehicles(myAgent)
        elif 'Control' in self.tactic:
            self.plan_control(myAgent)
        elif 'CleanCities_2' in self.tactic:
            self.plan_clean_cities_2(myAgent)
        elif 'Defend' in self.tactic:
            self.plan_defend(myAgent)

        # 零星任务
        self.control_4540(myAgent)

        # 炮兵任务
        self.pao_bing.plan(self, myAgent)

        # 应急响应
        self.control_neighbor(myAgent)
        self.hide_drone(myAgent)
        self.hide_helicopter(myAgent)

        # print(f"\t|= current tactic: {self.tactic}")

    def init_groups(self):
        self.group_static['pao_bing'] = [BlueOprs.PaoBingQun.Artillery_0, BlueOprs.PaoBingQun.Artillery_1,
                                         BlueOprs.PaoBingQun.Artillery_2, BlueOprs.PaoBingQun.Artillery_3,
                                         BlueOprs.PaoBingQun.Artillery_4, BlueOprs.PaoBingQun.Artillery_5]
        self.group_info['pao_bing'] = {'group_task': [], 'obj_ids': self.group_static['pao_bing']}
        self.group_static['zhi_sheng_ji'] = [BlueOprs.ZhiShengJi.Helicopter_0, BlueOprs.ZhiShengJi.Helicopter_1]
        self.group_info['zhi_sheng_ji'] = {'group_task': [], 'obj_ids': self.group_static['zhi_sheng_ji']}
        self.group_static['wu_ren_ji'] = [BlueOprs.WuRenJi.Drone_0, BlueOprs.WuRenJi.Drone_1]
        self.group_info['wu_ren_ji'] = {'group_task': [], 'obj_ids': self.group_static['wu_ren_ji']}
        self.group_static['tan_ke'] = [BlueOprs.XianQianDui_1.Tank_0, BlueOprs.XianQianDui_1.Tank_1,
                                       BlueOprs.XianQianDui_2.Tank_0, BlueOprs.XianQianDui_2.Tank_1,
                                       BlueOprs.XianQianDui_3.Tank_0, BlueOprs.XianQianDui_3.Tank_1,
                                       BlueOprs.XianQianDui_4.Tank_0, BlueOprs.XianQianDui_4.Tank_1]
        self.group_info['tan_ke'] = {'group_task': [], 'obj_ids': self.group_static['tan_ke']}
        self.group_static['zhan_che'] = [BlueOprs.XianQianDui_1.IFV_0, BlueOprs.XianQianDui_1.IFV_1,
                                         BlueOprs.XianQianDui_2.IFV_0, BlueOprs.XianQianDui_2.IFV_1,
                                         BlueOprs.XianQianDui_3.IFV_0, BlueOprs.XianQianDui_3.IFV_1,
                                         BlueOprs.XianQianDui_4.IFV_0, BlueOprs.XianQianDui_4.IFV_1]
        self.group_info['zhan_che'] = {'group_task': [], 'obj_ids': self.group_static['zhan_che']}
        self.group_static['bu_bing'] = [BlueOprs.XianQianDui_1.Infantry_0, BlueOprs.XianQianDui_1.Infantry_1,
                                         BlueOprs.XianQianDui_2.Infantry_0, BlueOprs.XianQianDui_2.Infantry_1,
                                         BlueOprs.XianQianDui_3.Infantry_0, BlueOprs.XianQianDui_3.Infantry_1,
                                         BlueOprs.XianQianDui_4.Infantry_0, BlueOprs.XianQianDui_4.Infantry_1]
        self.group_info['bu_bing'] = {'group_task': [], 'obj_ids': self.group_static['bu_bing']}

    def remove_group_dead_members(self, myAgent):
        """删除group_info中的已死亡算子，group_static不变化"""
        for obj_id in self.group_info['pao_bing']['obj_ids']:
            if not myAgent.get_bop(obj_id):
                self.group_info['pao_bing']['obj_ids'].remove(obj_id)
        for obj_id in self.group_info['zhi_sheng_ji']['obj_ids']:
            if not myAgent.get_bop(obj_id):
                self.group_info['zhi_sheng_ji']['obj_ids'].remove(obj_id)
        for obj_id in self.group_info['wu_ren_ji']['obj_ids']:
            if not myAgent.get_bop(obj_id):
                self.group_info['wu_ren_ji']['obj_ids'].remove(obj_id)
        for obj_id in self.group_info['tan_ke']['obj_ids']:
            if not myAgent.get_bop(obj_id):
                self.group_info['tan_ke']['obj_ids'].remove(obj_id)
        for obj_id in self.group_info['zhan_che']['obj_ids']:
            if not myAgent.get_bop(obj_id):
                self.group_info['zhan_che']['obj_ids'].remove(obj_id)
        for obj_id in self.group_info['bu_bing']['obj_ids']:
            if not myAgent.get_bop(obj_id):
                self.group_info['bu_bing']['obj_ids'].remove(obj_id)

    def regroup_oprs(self, myAgent):
        """重新分组"""
        """=== 空闲算子按照group_static进行分组 ==="""
        our_oprs = myAgent.get_our_oprs()
        for opr in our_oprs:
            opr_id = opr['obj_id']
            regroup_flag = False
            if opr_id in self.task.keys():
                if self.task[opr_id][0] in ['Success', 'Failure', 'Error'] and opr['on_board'] == 0:
                    regroup_flag = True
            else:
                if opr['on_board'] == 0:
                    regroup_flag = True
            if regroup_flag:
                group_name = None
                for name, obj_ids in self.group_static.items():
                    if opr_id in obj_ids:
                        group_name = name
                if group_name:
                    if opr_id not in self.group_info[group_name]['obj_ids']:
                        self.group_info[group_name]['obj_ids'].append(opr_id)
                if self.task_backup.get(opr_id):  # 如果空闲算子在self.task_backup中有备份，继续备份中的任务
                    self.task[opr_id] = self.task_backup.pop(opr_id)

        """=== 调整分组 ==="""

    def control_neighbor(self, myAgent):
        """算子处于邻格时，快速夺控"""
        enemies = myAgent.situations.enemies
        for opr in myAgent.get_our_oprs():
            if opr['type'] == BopType.Aircraft:
                continue
            if opr['type'] == BopType.Artillery:
                continue
            opr_loc = opr['cur_hex']
            for city in myAgent.observation['cities']:
                city_loc = city['coord']
                if city['flag'] == self.color:
                    continue
                if cal_distance(opr_loc, city_loc) > 1:
                    continue
                flag_enemy_by_city = False
                for enemy_info in enemies:
                    if not enemy_info['spread_flag']:
                        continue
                    if enemy_info['operator']['type'] == BopType.Aircraft:
                        continue
                    enemy_loc = enemy_info['operator']['cur_hex']
                    if cal_distance(enemy_loc, city_loc) <= 1:
                        flag_enemy_by_city = True
                        break
                if not flag_enemy_by_city:
                    if self.task.get(opr['obj_id']):
                        if 'try_control' not in self.task[opr['obj_id']] and not self.task_backup.get(
                                opr['obj_id']):
                            self.task_backup[opr['obj_id']] = self.task.pop(opr['obj_id'])
                    self.task[opr['obj_id']] = ['try_control', city_loc]

    def hide_helicopter(self, myAgent):
        # 遭到直升机突袭的反应策略（不考虑车辆的反应）
        map_size = myAgent.get_map_size()
        n_hexes = map_size['row'] * map_size['col']
        dist_matrix = myAgent.my_map['dist_matrix']
        see_matrix = myAgent.my_map['see_matrix'][2]
        enemy_heli_0 = myAgent.get_bop(BlueOprs.ZhiShengJi.Helicopter_0)
        enemy_heli_1 = myAgent.get_bop(BlueOprs.ZhiShengJi.Helicopter_1)
        if not enemy_heli_0 and not enemy_heli_1:
            return
        enemy_helis = []
        if enemy_heli_0:
            enemy_helis.append(enemy_heli_0)
        if enemy_heli_1:
            enemy_helis.append(enemy_heli_1)
        # 计算直升机的威胁范围
        # threat_area_vehicle_bool = np.zeros(n_hexes, dtype=bool)
        shoot_area_infantry_bool = np.zeros(n_hexes, dtype=bool)
        for heli in enemy_helis:
            # heli_info = myAgent.get_enemy_info(heli['obj_id'])
            heli_loc_ind = mapid_2_matind(heli['cur_hex'], map_size)
            # threat_area_vehicle_bool = np.logical_or(threat_area_vehicle_bool,
            #                                          get_opr_shoot_range(heli, BopType.Vehicle, myAgent,
            #                                                              heli['carry_weapon_ids'],
            #                                                              heli_info['remain_bullet_nums']))
            shoot_area_infantry_bool = np.logical_or(
                shoot_area_infantry_bool, np.logical_and(dist_matrix[heli_loc_ind] <= 10, see_matrix[heli_loc_ind]))
        # threat_area_vehicle = list(matind_2_mapid(np.arange(n_hexes)[threat_area_vehicle_bool], map_size))
        shoot_area_infantry = list(matind_2_mapid(np.arange(n_hexes)[shoot_area_infantry_bool], map_size))
        for opr in myAgent.get_our_oprs():
            if opr['type'] == BopType.Infantry:
                """步兵的反应：停下来准备射击"""
                if opr['remain_bullet_nums'][BulletType.HeavyMissile] <= 0:
                    continue
                if opr['cur_hex'] not in shoot_area_infantry:
                    continue
                ambush_loc = opr['move_path'][-1] if opr['move_path'] else opr['cur_hex']
                if self.task.get(opr['obj_id']):
                    if 'air_defense' not in self.task[opr['obj_id']] and not self.task_backup.get(
                            opr['obj_id']):  # 本策略中'air_defense'的任务只用于步兵打直升机
                        self.task_backup[opr['obj_id']] = self.task.pop(opr['obj_id'])
                self.task[opr['obj_id']] = ['air_defense', ambush_loc]
            # elif opr['type'] == BopType.Vehicle:
            #     """车辆的反应：能逃就逃"""
            #     if opr['cur_hex'] not in threat_area_vehicle:
            #         continue
            #     if self.task.get(opr['obj_id']):
            #         if 'hide' not in self.task[opr['obj_id']] and not self.task_backup.get(opr['obj_id']):
            #             self.task_backup[opr['obj_id']] = self.task.pop(opr['obj_id'])
            #         self.task[opr['obj_id']] = ['hide']

    def hide_drone(self, myAgent):
        enemy_drones = [myAgent.get_bop(RedOprs.WuRenJi.Drone_0), myAgent.get_bop(RedOprs.WuRenJi.Drone_1)]
        for opr in myAgent.get_our_oprs():
            if opr['type'] == BopType.Infantry:  # 步兵对无人机打击
                if opr['remain_bullet_nums'][BulletType.HeavyMissile] <= 0:
                    continue
                flag_drone_in_sight = False
                for enemy_drone in enemy_drones:
                    if not enemy_drone:
                        continue
                    if cal_distance(enemy_drone['cur_hex'], opr['cur_hex']) <= 1:
                        flag_drone_in_sight = True
                if not flag_drone_in_sight:
                    continue
                ambush_loc = opr['move_path'][-1] if opr['move_path'] else opr['cur_hex']
                if self.task.get(opr['obj_id']):
                    if 'air_defense' not in self.task[opr['obj_id']] and not self.task_backup.get(opr['obj_id']):
                        self.task_backup[opr['obj_id']] = self.task.pop(opr['obj_id'])
                self.task[opr['obj_id']] = ['air_defense', ambush_loc]

    def make_tactic(self, myAgent):
        if myAgent.observation['time']['cur_step'] > 2500:
            n_enemy_tank_ifv = 0
            for enemy_info in myAgent.situations.enemies:
                enemy = enemy_info['operator']
                if enemy['sub_type'] in [BopType.Tank, BopType.IFV]:
                    n_enemy_tank_ifv += 1
            if len(self.group_info['tan_ke']['obj_ids']) > 3 or n_enemy_tank_ifv <= 2:
                self.tactic = ['Control']
        elif not self.tactic:
            fastest_infantry_loc = 9999
            for opr in myAgent.get_our_oprs():
                if opr['type'] == BopType.Infantry:
                    if opr['cur_hex'] < fastest_infantry_loc:
                        fastest_infantry_loc = opr['cur_hex']
            # n_tanks, n_tanks_in_postion = 0., 0.
            # n_infantries, n_infantries_in_position = 0., 0.
            # for opr in myAgent.get_our_oprs():
            #     if opr['sub_type'] == BopType.Tank:
            #         n_tanks += 1.
            #         if opr['obj_id'] == BlueOprs.XianQianDui_1.Tank_0 and opr['cur_hex'] < 4500:
            #             n_tanks_in_postion += 1
            #         elif opr['cur_hex'] < 4400:
            #             n_tanks_in_postion += 1.
            #     elif opr['type'] == BopType.Infantry:
            #         if opr['obj_id'] == BlueOprs.XianQianDui_1.Infantry_0:
            #             continue
            #         n_infantries += 1.
            #         if opr['cur_hex'] < 4300:
            #             n_infantries_in_position += 1.
            # if n_tanks_in_postion / n_tanks >= 0.75 and n_infantries_in_position / n_infantries >= 0.75:
            if fastest_infantry_loc < 4200:
                # 清理右侧夺控区域
                tar_area = get_range(3744, 3, myAgent.get_map_size()) + list(range(4140, 4147)) \
                           + list(range(4241, 4148)) + get_range(4540, 1, myAgent.get_map_size())
                self.tactic = ['CleanCities_1', tar_area]
        elif 'CleanCities_1' in self.tactic:
            tar_area = self.tactic[1]
            flag_enemy_in_tar_area = False
            n_enemy_tanks = 0
            for enemy_info in myAgent.situations.enemies:
                if not enemy_info['spread_flag']:
                    continue
                enemy = enemy_info['operator']
                if enemy['type'] == BopType.Aircraft:
                    continue
                if enemy['cur_hex'] in tar_area:
                    flag_enemy_in_tar_area = True
                    break
            for enemy_info in myAgent.situations.enemies:
                enemy = enemy_info['operator']
                if enemy['sub_type'] == BopType.Tank:
                    n_enemy_tanks += 1
            if flag_enemy_in_tar_area:
                return
            if n_enemy_tanks >= 3:
                return
            n_tanks = 0
            for opr in myAgent.get_our_oprs():
                if opr['sub_type'] == BopType.Tank:
                    n_tanks += 1
            if n_tanks - n_enemy_tanks < 2:
                self.tactic = ['Defend']  # 防守右路区域
            else:
                tar_area_2 = []  # 确定搜索区域
                for row in range(26, 35):
                    for col in range(42, 48):
                        tar_area_2.append(row * 100 + col)
                clean_oprs = []
                for opr in myAgent.get_our_oprs():
                    if opr['sub_type'] == BopType.Tank:
                        clean_oprs.append(opr['obj_id'])
                n_enemy_ifv = 0
                for enemy_info in myAgent.situations.enemies:
                    if enemy_info['operator']['sub_type'] == BopType.IFV:
                        n_enemy_ifv += 1
                if n_enemy_ifv >= 2:
                    self.tactic = ['SearchVehicle', tar_area_2, clean_oprs]
                else:
                    tar_area_2 = get_range(3839, 2, myAgent.get_map_size())
                    self.tactic = ['CleanCities_2', tar_area_2]
                # tar_area_2 = get_range(3839, 2, myAgent.get_map_size())
                # clean_oprs, support_oprs, control_oprs = [], [], []
                # for obj_id in self.tactic[3]:
                #     if myAgent.get_bop(obj_id):
                #         support_oprs.append(obj_id)
                # for obj_id in self.tactic[4]:
                #     if myAgent.get_bop(obj_id):
                #         control_oprs.append(obj_id)
                # for opr in myAgent.get_our_oprs():
                #     if opr['obj_id'] in support_oprs + control_oprs:
                #         continue
                #     if opr['type'] == BopType.Aircraft or opr['sub_type'] == BopType.Artillery:
                #         continue
                #     if opr['type'] == BopType.Infantry:
                #         continue
                #     clean_oprs.append(opr['obj_id'])
                # self.tactic = ['CleanCities_2', tar_area_2, clean_oprs, support_oprs, control_oprs]
        elif 'CleanCities_2' in self.tactic:
            tar_area = self.tactic[1]
            flag_enemy_in_tar_area = False
            for enemy_info in myAgent.situations.enemies:
                if not enemy_info['spread_flag']:
                    continue
                enemy = enemy_info['operator']
                if enemy['type'] == BopType.Aircraft:
                    continue
                if enemy['cur_hex'] in tar_area:
                    flag_enemy_in_tar_area = True
                    break
            if flag_enemy_in_tar_area:
                return
            self.tactic = ['Defend']  # 防守左路区域
        elif 'SearchVehicle' in self.tactic:
            our_tank_ids = self.group_info['tan_ke']['obj_ids']
            if our_tank_ids:
                for tk_id in our_tank_ids:
                    if 'search_clean' in self.task.get(tk_id, []):
                        return
            tar_area_2 = get_range(3839, 2, myAgent.get_map_size())
            self.tactic = ['CleanCities_2', tar_area_2]

    def plan_clean_cities_1(self, myAgent):
        # 筛选攻击区域
        tar_area = self.tactic[1]
        enemies_tar_area = []
        for enemy_info in myAgent.situations.enemies:
            if not enemy_info['spread_flag']:
                continue
            enemy = enemy_info['operator']
            if enemy['type'] == BopType.Aircraft:
                continue
            if enemy['cur_hex'] in tar_area:
                enemies_tar_area.append(enemy)
        # if not enemies_tar_area:
        #     return
        # 分派攻击任务
        attack_opr_ids = []
        for opr in myAgent.get_our_oprs():
            if opr['sub_type'] == BopType.Tank:
                attack_opr_ids.append(opr['obj_id'])
            elif opr['sub_type'] == BopType.IFV:
                if 'ambush4th' in self.task.get(opr['obj_id'], []):
                    if self.task[opr['obj_id']][1] in [4736, 4736, 4838]:
                        continue
                if 'deliver' in self.task[opr['obj_id']]:
                    continue
                attack_opr_ids.append(opr['obj_id'])
        for obj_id in attack_opr_ids:
            opr = myAgent.get_bop(obj_id)
            if not opr:
                continue
            # cur_tar = min(enemies, key=lambda ene: cal_distance(ene['cur_hex'], opr['cur_hex']))
            # self.task[obj_id] = ['targeted_kill', cur_tar['obj_id']]
            if opr['type'] == BopType.Infantry:
                continue
            if enemies_tar_area:
                self.task[obj_id] = ['assult', [enemy['obj_id'] for enemy in enemies_tar_area]]
            else:
                if self.task.get(obj_id):
                    if 'ambush4th' not in self.task[obj_id]:
                        tar_loc = random.choice(get_range(4045, 1, myAgent.get_map_size()) + [3946, 4143])
                        if opr['sub_type'] == BopType.Tank:
                            self.task[obj_id] = ['ambush4th', tar_loc, False]
                        else:
                            self.task[obj_id] = ['ambush4th', tar_loc, True]
        # 分派支援任务
        # support_oprs = self.tactic[3]
        # for obj_id in support_oprs:
        #     ifv = myAgent.get_bop(obj_id)
        #     if not ifv:
        #         support_oprs.remove(obj_id)
        #         continue
        #     if ifv['cur_hex'] == 4736:
        #         self.task[obj_id] = ['ambush4th', 4736, True]
        #     elif ifv['cur_hex'] == 4838:
        #         self.task[obj_id] = ['ambush4th', 4838, True]
        # 分派夺控任务
        # control_opr = self.tactic[4][0]
        # if myAgent.get_bop(control_opr):
        #     city = myAgent.get_city(4540)
        #     if city['flag'] != self.color:
        #         self.task[control_opr] = ['control', 4540]
        #     else:
        #         self.task[control_opr] = ['defend_firepower', 4540, []]

    def plan_clean_cities_2(self, myAgent):
        # 筛选攻击区域
        tar_area = self.tactic[1]
        our_tank_ids = self.group_info['tan_ke']['obj_ids']
        for tk_id in our_tank_ids:
            if not myAgent.get_bop(tk_id):
                continue
            if self.task.get(tk_id):
                if 'search_clean' in self.task[tk_id] and self.task[tk_id][1] > 3600 and self.task[tk_id][1] % 100 < 41:
                    continue
            self.task[tk_id] = ['search_clean', random.choice([3837, 3939])]
        used_ifv_ids = self.group_info['zhan_che']['obj_ids']
        for ifv_id in used_ifv_ids:
            ifv = myAgent.get_bop(ifv_id)
            if not ifv:
                continue
            self.task[ifv_id] = ['output_firepower', tar_area]
        # enemies_tar_area = []
        # for enemy_info in myAgent.situations.enemies:
        #     if not enemy_info['spread_flag']:
        #         continue
        #     enemy = enemy_info['operator']
        #     if enemy['type'] == BopType.Aircraft:
        #         continue
        #     if enemy['cur_hex'] in tar_area:
        #         enemies_tar_area.append(enemy)
        # if not enemies_tar_area:
        #     return
        # # 区分敌方算子类型
        # enemies_vehicle, enemies_infantry = [], []
        # for enemy in enemies_tar_area:
        #     if enemy['type'] == BopType.Vehicle:
        #         enemies_vehicle.append(enemy)
        #     elif enemy['type'] == BopType.Infantry:
        #         enemies_infantry.append(enemy)
        # enemies = enemies_vehicle if enemies_vehicle else enemies_infantry
        # # 分派支援任务
        # support_oprs = self.tactic[3]
        # for obj_id in support_oprs:
        #     opr = myAgent.get_bop(obj_id)
        #     if not opr:
        #         support_oprs.remove(obj_id)
        #         continue
        #     support_loc = min([4736, 4838], key=lambda loc: cal_distance(loc, opr['cur_hex']))
        #     self.task[obj_id] = ['ambush4th', support_loc, True]
        # # 分派夺控任务
        # used_oprs = self.tactic[2] + self.tactic[4]
        # for obj_id in used_oprs:
        #     if not myAgent.get_bop(obj_id):
        #         used_oprs.remove(obj_id)
        # control_oprs = []
        # for city_loc in [4540, 4246, 3947, 3747]:
        #     min_dist, cur_ctrl_opr = 1000, None
        #     for obj_id in used_oprs:
        #         opr = myAgent.get_bop(obj_id)
        #         if not opr:
        #             continue
        #         if obj_id in support_oprs:
        #             continue
        #         if opr['type'] == BopType.Infantry:
        #             cur_dist = cal_distance(opr['cur_hex'], city_loc)
        #         elif opr['sub_type'] == BopType.IFV:
        #             cur_dist = cal_distance(opr['cur_hex'], city_loc) + 5
        #         elif opr['sub_type'] == BopType.Tank:
        #             cur_dist = cal_distance(opr['cur_hex'], city_loc) + 10
        #         else:
        #             cur_dist = 1000
        #         if cur_dist < min_dist:
        #             min_dist = cur_dist
        #             cur_ctrl_opr = opr['obj_id']
        #     if min_dist >= 1000:
        #         continue
        #     control_oprs.append(cur_ctrl_opr)
        #     used_oprs.remove(cur_ctrl_opr)
        #     city = myAgent.get_city(city_loc)
        #     if city['flag'] != self.color:
        #         self.task[cur_ctrl_opr] = ['control', city_loc]
        #     else:
        #         self.task[cur_ctrl_opr] = ['defend_firepower', city_loc, []]
        # self.tactic[2] = used_oprs
        # self.tactic[4] = control_oprs
        # # 分派攻击任务
        # for obj_id in used_oprs:
        #     opr = myAgent.get_bop(obj_id)
        #     if not opr:
        #         continue
        #     # cur_tar = min(enemies, key=lambda ene: cal_distance(ene['cur_hex'], opr['cur_hex']))
        #     # self.task[obj_id] = ['targeted_kill', cur_tar['obj_id']]
        #     self.task[obj_id] = ['assult', [enemy['obj_id'] for enemy in enemies]]

    def plan_search_vehicles(self, myAgent):
        tar_area = list(range(2843, 2847))
        our_tank_ids = self.group_info['tan_ke']['obj_ids']
        for tk_id in our_tank_ids:
            if not myAgent.get_bop(tk_id):
                continue
            if self.task.get(tk_id):
                if 'search_clean' in self.task[tk_id] and self.task[tk_id][1] < 2900:
                    continue
            self.task[tk_id] = ['search_clean', random.choice(tar_area)]

    def plan_control(self, myAgent):
        our_tanks = []
        for opr in myAgent.get_our_oprs():
            if opr['sub_type'] == BopType.Tank:
                our_tanks.append(opr)
        other_cities = []
        for city in myAgent.observation['cities']:
            if city['flag'] != self.color:
                flag_enemy_around = False
                for enemy_info in myAgent.situations.enemies:
                    if not enemy_info['spread_flag']:
                        continue
                    enemy = enemy_info['operator']
                    if enemy['type'] == BopType.Aircraft:
                        continue
                    if cal_distance(enemy['cur_hex'], city['coord']) <= 1:
                        flag_enemy_around = True
                        break
                if not flag_enemy_around:
                    other_cities.append(city)
        if our_tanks:
            control_candidates = our_tanks
        else:
            control_candidates = []
            for opr in myAgent.get_our_oprs():
                if opr['type'] == BopType.Vehicle and opr['sub_type'] != BopType.Artillery:
                    control_candidates.append(opr)
        min_dist = 1000
        best_opr, best_city = None, None
        for opr in control_candidates:
            for city in other_cities:
                cur_dist = cal_distance(city['coord'], opr['cur_hex'])
                if min_dist > cur_dist:
                    best_opr = opr
                    best_city = city
                    min_dist = cur_dist
        if best_opr and best_city:
            self.task[best_opr['obj_id']] = ['control', best_city['coord']]
            # 为非夺控算子分派任务
            assult_oprs = []
            for opr in myAgent.get_our_oprs():
                if 'control' in self.task.get(opr['obj_id'], []):
                    continue
                if opr['sub_type'] == BopType.UCV:
                    assult_oprs.append(opr)
                elif opr['sub_type'] == BopType.IFV:
                    assult_oprs.append(opr)
                elif opr['sub_type'] == BopType.Tank:
                    assult_oprs.append(opr)
            enemies_around_city = []
            for enemy_info in myAgent.situations.enemies:
                if not enemy_info['spread_flag']:
                    continue
                enemy = enemy_info['operator']
                dist_cities = cal_distance(enemy['cur_hex'], best_city['coord'])
                if dist_cities <= 3:
                    if enemy['type'] != BopType.Aircraft:
                        enemies_around_city.append(enemy)
            if enemies_around_city:
                for opr in assult_oprs:
                    self.task[opr['obj_id']] = ['assult', [enemy['obj_id'] for enemy in enemies_around_city]]
            else:
                for opr in assult_oprs:
                    if opr['sub_type'] == BopType.Tank:
                        if self.task.get(opr['obj_id']):
                            if 'ambush4th' in self.task[opr['obj_id']] and cal_distance(self.task[opr['obj_id']][1],
                                                                                        best_city['coord']) <= 3:
                                continue
                        self.task[opr['obj_id']] = ['ambush4th', random.choice(get_range(best_city['coord'], 3, myAgent.get_map_size())), False]
                    else:
                        self.task[opr['obj_id']] = ['output_firepower', get_range(best_city['coord'], 3, myAgent.get_map_size())]
        # 为步兵算子分派任务
        for opr in myAgent.get_our_oprs():
            if opr['type'] == BopType.Infantry:
                if min([cal_distance(opr['cur_hex'], city['coord']) for city in myAgent.observation['cities']]) <= 1:
                    self.task[opr['obj_id']] = ['guard2nd', True]
                else:
                    cloest_city = min(myAgent.observation['cities'],
                                      key=lambda city: cal_distance(opr['cur_hex'], city['coord']))
                    self.task[opr['obj_id']] = ['maneuver', get_line(cloest_city['coord'], opr['cur_hex'])[0]]

    def plan_defend(self, myAgent):
        for opr in myAgent.get_our_oprs():
            flag_round_city = False
            cur_city = None
            for city in myAgent.observation['cities']:
                if cal_distance(opr['cur_hex'], city['coord']) <= 1:
                    flag_round_city = True
                    cur_city = city
                    break
            if flag_round_city:
                if cur_city['flag'] != self.color:
                    self.task[opr['obj_id']] = ['control', cur_city['coord']]
                else:
                    self.task[opr['obj_id']] = ['defend_firepower', cur_city['coord'], []]
            else:
                self.task[opr['obj_id']] = ['guard2nd', True]

    def control_4540(self, myAgent):
        infantry_3_1 = myAgent.get_bop(BlueOprs.XianQianDui_3.Infantry_1)
        if infantry_3_1:
            if infantry_3_1['get_off_remain_time'] > 0:
                self.task[infantry_3_1['obj_id']] = ['guard2nd', True]
                ifv_id = infantry_3_1['car']
                if myAgent.get_bop(ifv_id):
                    self.task[ifv_id] = ['ambush4th', 4737, False]


class TanKe:
    """坦克组的策略实现"""

    def __init__(self, factionAI):
        self.members = factionAI.group_static['tan_ke']
        self.group_task = ['Deployment']
        self.tactic = None
        self.cur_step = 0

    def plan(self, factionAI, myAgent):
        self.cur_step = myAgent.observation['time']['cur_step']
        self.members = factionAI.group_info['tan_ke']['obj_ids']
        if not self.members:
            return

        # === 更新组任务 ===
        self.update_group_task(factionAI, myAgent)

        # === 分派算子任务 ===
        self.assign_opr_tasks(factionAI, myAgent)

    def update_group_task(self, factionAI, myAgent):
        if 'CleanCities_1' in factionAI.tactic:
            self.group_task = ['OutputFirepower']

    def assign_opr_tasks(self, factionAI, myAgent):
        tank_1_0, tank_1_1 = myAgent.get_bop(BlueOprs.XianQianDui_1.Tank_0), myAgent.get_bop(BlueOprs.XianQianDui_1.Tank_1)
        tank_2_0, tank_2_1 = myAgent.get_bop(BlueOprs.XianQianDui_2.Tank_0), myAgent.get_bop(BlueOprs.XianQianDui_2.Tank_1)
        tank_3_0, tank_3_1 = myAgent.get_bop(BlueOprs.XianQianDui_3.Tank_0), myAgent.get_bop(BlueOprs.XianQianDui_3.Tank_1)
        tank_4_0, tank_4_1 = myAgent.get_bop(BlueOprs.XianQianDui_4.Tank_0), myAgent.get_bop(BlueOprs.XianQianDui_4.Tank_1)

        if 'Deployment' in self.group_task:
            """=== 部署任务 ==="""
            # print(f'\t|= cur_step: {myAgent.observation["time"]["cur_step"]}')
            fastest_infantry_loc = 9999
            for opr in myAgent.get_our_oprs():
                if opr['type'] == BopType.Infantry:
                    if opr['cur_hex'] < fastest_infantry_loc:
                        fastest_infantry_loc = opr['cur_hex']
            if tank_1_0:
                # infantry_1_0 = myAgent.get_bop(BlueOprs.XianQianDui_1.Infantry_0)
                if tank_1_0['cur_hex'] == 6338:
                    factionAI.task[tank_1_0['obj_id']] = ['maneuver', 5650]
                if tank_1_0['cur_hex'] == 5650:
                    factionAI.task[tank_1_0['obj_id']] = ['guard2nd', True]
                if 570 <= self.cur_step < 890:
                    factionAI.task[tank_1_0['obj_id']] = ['maneuver', 4945]
                if self.cur_step >= 890 and fastest_infantry_loc > 4400:
                    # 找到最近的步兵
                    all_infantries = factionAI.group_info['bu_bing']['obj_ids']
                    if BlueOprs.XianQianDui_3.Infantry_1 in all_infantries:
                        all_infantries.remove(BlueOprs.XianQianDui_3.Infantry_1)
                    random.shuffle(all_infantries)
                    min_dist, co_inf = 1000, None
                    for inf_id in all_infantries:
                        inf = myAgent.get_bop(inf_id)
                        if not inf:
                            continue
                        cur_dist = cal_distance(tank_1_0['cur_hex'], inf['cur_hex'])
                        if cur_dist < min_dist:
                            min_dist = cur_dist
                            co_inf = inf
                    if co_inf:
                        factionAI.task[tank_1_0['obj_id']] = ['infantry_tank_coordination', co_inf['obj_id']]
                    else:
                        factionAI.task[tank_1_0['obj_id']] = ['maneuver', 4343]
                elif self.cur_step >= 890 and fastest_infantry_loc <= 4400:
                    factionAI.task[tank_1_0['obj_id']] = ['maneuver', 4343]
                if tank_1_0['cur_hex'] < 4400:
                    factionAI.task[tank_1_0['obj_id']] = ['guard2nd', True]
            if tank_1_1:
                # infantry_1_1 = myAgent.get_bop(BlueOprs.XianQianDui_1.Infantry_1)
                if tank_1_1['cur_hex'] == 6338:
                    factionAI.task[tank_1_1['obj_id']] = ['maneuver', 5548]
                if tank_1_1['cur_hex'] == 5548:
                    factionAI.task[tank_1_1['obj_id']] = ['guard2nd', True]
                if 660 <= self.cur_step < 900:
                    factionAI.task[tank_1_1['obj_id']] = ['maneuver', 4948]
                if self.cur_step >= 900 and fastest_infantry_loc > 4400:
                    # 找到最近的步兵
                    all_infantries = factionAI.group_info['bu_bing']['obj_ids']
                    if BlueOprs.XianQianDui_3.Infantry_1 in all_infantries:
                        all_infantries.remove(BlueOprs.XianQianDui_3.Infantry_1)
                    random.shuffle(all_infantries)
                    min_dist, co_inf = 1000, None
                    for inf_id in all_infantries:
                        inf = myAgent.get_bop(inf_id)
                        if not inf:
                            continue
                        cur_dist = cal_distance(tank_1_1['cur_hex'], inf['cur_hex'])
                        if cur_dist < min_dist:
                            min_dist = cur_dist
                            co_inf = inf
                    if co_inf:
                        factionAI.task[tank_1_1['obj_id']] = ['infantry_tank_coordination', co_inf['obj_id']]
                    else:
                        factionAI.task[tank_1_1['obj_id']] = ['maneuver', 4345]
                elif self.cur_step >= 900 and fastest_infantry_loc <= 4400:
                    factionAI.task[tank_1_1['obj_id']] = ['maneuver', 4345]
                if tank_1_1['cur_hex'] < 4400:
                    factionAI.task[tank_1_1['obj_id']] = ['guard2nd', True]
            if tank_2_0:
                # infantry_2_0 = myAgent.get_bop(BlueOprs.XianQianDui_2.Infantry_0)
                if tank_2_0['cur_hex'] == 6446:
                    factionAI.task[tank_2_0['obj_id']] = ['maneuver', 5550]
                if tank_2_0['cur_hex'] == 5550:
                    factionAI.task[tank_2_0['obj_id']] = ['guard2nd', True]
                if 480 <= self.cur_step < 760:
                    factionAI.task[tank_2_0['obj_id']] = ['maneuver', 5046]
                if self.cur_step >= 760 and fastest_infantry_loc > 4400:
                    # 找到最近的步兵
                    all_infantries = factionAI.group_info['bu_bing']['obj_ids']
                    if BlueOprs.XianQianDui_3.Infantry_1 in all_infantries:
                        all_infantries.remove(BlueOprs.XianQianDui_3.Infantry_1)
                    random.shuffle(all_infantries)
                    min_dist, co_inf = 1000, None
                    for inf_id in all_infantries:
                        inf = myAgent.get_bop(inf_id)
                        if not inf:
                            continue
                        cur_dist = cal_distance(tank_2_0['cur_hex'], inf['cur_hex'])
                        if cur_dist < min_dist:
                            min_dist = cur_dist
                            co_inf = inf
                    if co_inf:
                        factionAI.task[tank_2_0['obj_id']] = ['infantry_tank_coordination', co_inf['obj_id']]
                    else:
                        factionAI.task[tank_2_0['obj_id']] = ['maneuver', 4344]
                elif self.cur_step >= 760 and fastest_infantry_loc <= 4400:
                    factionAI.task[tank_2_0['obj_id']] = ['maneuver', 4344]
                if tank_2_0['cur_hex'] < 4400:
                    factionAI.task[tank_2_0['obj_id']] = ['guard2nd', True]
            if tank_2_1:
                # infantry_2_1 = myAgent.get_bop(BlueOprs.XianQianDui_2.Infantry_1)
                if tank_2_1['cur_hex'] == 6446:
                    factionAI.task[tank_2_1['obj_id']] = ['maneuver', 5653]
                if tank_2_1['cur_hex'] == 5653:
                    factionAI.task[tank_2_1['obj_id']] = ['guard2nd', True]
                if 460 <= self.cur_step < 780:
                    factionAI.task[tank_2_1['obj_id']] = ['maneuver', 5049]
                if self.cur_step >= 780 and fastest_infantry_loc > 4400:
                    # 找到最近的步兵
                    all_infantries = factionAI.group_info['bu_bing']['obj_ids']
                    if BlueOprs.XianQianDui_3.Infantry_1 in all_infantries:
                        all_infantries.remove(BlueOprs.XianQianDui_3.Infantry_1)
                    random.shuffle(all_infantries)
                    min_dist, co_inf = 1000, None
                    for inf_id in all_infantries:
                        inf = myAgent.get_bop(inf_id)
                        if not inf:
                            continue
                        cur_dist = cal_distance(tank_2_1['cur_hex'], inf['cur_hex'])
                        if cur_dist < min_dist:
                            min_dist = cur_dist
                            co_inf = inf
                    if co_inf:
                        factionAI.task[tank_2_1['obj_id']] = ['infantry_tank_coordination', co_inf['obj_id']]
                    else:
                        factionAI.task[tank_2_1['obj_id']] = ['maneuver', 4344]
                elif self.cur_step >= 780 and fastest_infantry_loc <= 4400:
                    factionAI.task[tank_2_1['obj_id']] = ['maneuver', 4344]
                if tank_2_1['cur_hex'] < 4400:
                    factionAI.task[tank_2_1['obj_id']] = ['guard2nd', True]
            if tank_3_0:
                # infantry_3_0 = myAgent.get_bop(BlueOprs.XianQianDui_3.Infantry_0)
                if fastest_infantry_loc > 4400:
                    # 找到最近的步兵
                    all_infantries = factionAI.group_info['bu_bing']['obj_ids']
                    if BlueOprs.XianQianDui_3.Infantry_1 in all_infantries:
                        all_infantries.remove(BlueOprs.XianQianDui_3.Infantry_1)
                    random.shuffle(all_infantries)
                    min_dist, co_inf = 1000, None
                    for inf_id in all_infantries:
                        inf = myAgent.get_bop(inf_id)
                        if not inf:
                            continue
                        cur_dist = cal_distance(tank_3_0['cur_hex'], inf['cur_hex'])
                        if cur_dist < min_dist:
                            min_dist = cur_dist
                            co_inf = inf
                    if co_inf:
                        factionAI.task[tank_3_0['obj_id']] = ['infantry_tank_coordination', co_inf['obj_id']]
                    else:
                        factionAI.task[tank_3_0['obj_id']] = ['maneuver', 4345]
                else:
                    factionAI.task[tank_3_0['obj_id']] = ['maneuver', 4345]
                if tank_3_0['cur_hex'] < 4400:
                    factionAI.task[tank_3_0['obj_id']] = ['guard2nd', True]
            if tank_3_1:
                # infantry_3_1 = myAgent.get_bop(BlueOprs.XianQianDui_3.Infantry_1)
                if tank_3_1['cur_hex'] == 5451 and self.cur_step < 280:
                    factionAI.task[tank_3_1['obj_id']] = ['guard2nd', True]
                if 280 <= self.cur_step < 360:
                    factionAI.task[tank_3_1['obj_id']] = ['maneuver', 5349]
                if self.cur_step >= 360 and fastest_infantry_loc > 4400:
                    # 找到最近的步兵
                    all_infantries = factionAI.group_info['bu_bing']['obj_ids']
                    if BlueOprs.XianQianDui_3.Infantry_1 in all_infantries:
                        all_infantries.remove(BlueOprs.XianQianDui_3.Infantry_1)
                    random.shuffle(all_infantries)
                    min_dist, co_inf = 1000, None
                    for inf_id in all_infantries:
                        inf = myAgent.get_bop(inf_id)
                        if not inf:
                            continue
                        cur_dist = cal_distance(tank_3_1['cur_hex'], inf['cur_hex'])
                        if cur_dist < min_dist:
                            min_dist = cur_dist
                            co_inf = inf
                    if co_inf:
                        factionAI.task[tank_3_1['obj_id']] = ['infantry_tank_coordination', co_inf['obj_id']]
                    else:
                        factionAI.task[tank_3_1['obj_id']] = ['maneuver', 4346]
                elif self.cur_step >= 360 and fastest_infantry_loc <= 4400:
                    factionAI.task[tank_3_1['obj_id']] = ['maneuver', 4346]
                if tank_3_1['cur_hex'] < 4400:
                    factionAI.task[tank_3_1['obj_id']] = ['guard2nd', True]
            if tank_4_0:
                # infantry_4_0 = myAgent.get_bop(BlueOprs.XianQianDui_4.Infantry_0)
                if fastest_infantry_loc > 4400:
                    # 找到最近的步兵
                    all_infantries = factionAI.group_info['bu_bing']['obj_ids']
                    if BlueOprs.XianQianDui_3.Infantry_1 in all_infantries:
                        all_infantries.remove(BlueOprs.XianQianDui_3.Infantry_1)
                    random.shuffle(all_infantries)
                    min_dist, co_inf = 1000, None
                    for inf_id in all_infantries:
                        inf = myAgent.get_bop(inf_id)
                        if not inf:
                            continue
                        cur_dist = cal_distance(tank_4_0['cur_hex'], inf['cur_hex'])
                        if cur_dist < min_dist:
                            min_dist = cur_dist
                            co_inf = inf
                    if co_inf:
                        factionAI.task[tank_4_0['obj_id']] = ['infantry_tank_coordination', co_inf['obj_id']]
                    else:
                        factionAI.task[tank_4_0['obj_id']] = ['maneuver', 4347]
                else:
                    factionAI.task[tank_4_0['obj_id']] = ['maneuver', 4347]
                if tank_4_0['cur_hex'] < 4400:
                    factionAI.task[tank_4_0['obj_id']] = ['guard2nd', True]
            if tank_4_1:
                # infantry_4_1 = myAgent.get_bop(BlueOprs.XianQianDui_4.Infantry_1)
                if tank_4_1['cur_hex'] == 5455 and self.cur_step < 200:
                    factionAI.task[tank_4_1['obj_id']] = ['guard2nd', True]
                if 200 <= self.cur_step < 360:
                    factionAI.task[tank_4_1['obj_id']] = ['maneuver', 5253]
                if self.cur_step >= 360 and fastest_infantry_loc > 4400:
                    # 找到最近的步兵
                    all_infantries = factionAI.group_info['bu_bing']['obj_ids']
                    if BlueOprs.XianQianDui_3.Infantry_1 in all_infantries:
                        all_infantries.remove(BlueOprs.XianQianDui_3.Infantry_1)
                    random.shuffle(all_infantries)
                    min_dist, co_inf = 1000, None
                    for inf_id in all_infantries:
                        inf = myAgent.get_bop(inf_id)
                        if not inf:
                            continue
                        cur_dist = cal_distance(tank_4_1['cur_hex'], inf['cur_hex'])
                        if cur_dist < min_dist:
                            min_dist = cur_dist
                            co_inf = inf
                    if co_inf:
                        factionAI.task[tank_4_1['obj_id']] = ['infantry_tank_coordination', co_inf['obj_id']]
                    else:
                        factionAI.task[tank_4_1['obj_id']] = ['maneuver', 4346]
                elif self.cur_step >= 360 and fastest_infantry_loc <= 4400:
                    factionAI.task[tank_4_1['obj_id']] = ['maneuver', 4346]
                if tank_4_1['cur_hex'] < 4400:
                    factionAI.task[tank_4_1['obj_id']] = ['guard2nd', True]
        elif 'OutputFirepower' in self.group_task:
            """=== 火力输出任务 ==="""
            pass


class ZhanChe:
    """战车组的策略实现"""

    def __init__(self, factionAI):
        self.members = factionAI.group_static['zhan_che']
        self.group_task = ['Deployment']
        self.tactic = None
        self.cur_step = 0

    def plan(self, factionAI, myAgent):
        self.cur_step = myAgent.observation['time']['cur_step']
        self.members = factionAI.group_info['zhan_che']['obj_ids']
        if not self.members:
            return

        # === 更新组任务 ===
        self.update_group_task(factionAI, myAgent)

        # === 分派算子任务 ===
        self.assign_opr_tasks(factionAI, myAgent)

    def update_group_task(self, factionAI, myAgent):
        if 'Deployment' in self.group_task:
            fastest_infantry_loc = 9999
            for opr in myAgent.get_our_oprs():
                if opr['type'] == BopType.Infantry:
                    if opr['cur_hex'] < fastest_infantry_loc:
                        fastest_infantry_loc = opr['cur_hex']
            if fastest_infantry_loc < 4500:
                self.group_task = ['Gather', 0]

    def assign_opr_tasks(self, factionAI, myAgent):
        ifv_1_0, ifv_1_1 = myAgent.get_bop(BlueOprs.XianQianDui_1.IFV_0), myAgent.get_bop(BlueOprs.XianQianDui_1.IFV_1)
        ifv_2_0, ifv_2_1 = myAgent.get_bop(BlueOprs.XianQianDui_2.IFV_0), myAgent.get_bop(BlueOprs.XianQianDui_2.IFV_1)
        ifv_3_0, ifv_3_1 = myAgent.get_bop(BlueOprs.XianQianDui_3.IFV_0), myAgent.get_bop(BlueOprs.XianQianDui_3.IFV_1)
        ifv_4_0, ifv_4_1 = myAgent.get_bop(BlueOprs.XianQianDui_4.IFV_0), myAgent.get_bop(BlueOprs.XianQianDui_4.IFV_1)

        if 'Deployment' in self.group_task:
            if ifv_1_0:
                infantry_1_0 = myAgent.get_bop(BlueOprs.XianQianDui_1.Infantry_0)
                if infantry_1_0:
                    if ifv_1_0['cur_hex'] == 6337 and infantry_1_0['on_board'] == 0 and infantry_1_0['get_on_remain_time'] <= 0:
                        factionAI.task[ifv_1_0['obj_id']] = ['load', infantry_1_0['obj_id']]
                    if ifv_1_0['cur_hex'] == 6337 and infantry_1_0['get_on_remain_time'] > 0:
                        factionAI.task[ifv_1_0['obj_id']] = ['maneuver', 6339]
                    if ifv_1_0['cur_hex'] == 6339:
                        factionAI.task[ifv_1_0['obj_id']] = ['maneuver', 6344]
                    if ifv_1_0['cur_hex'] == 6344:
                        factionAI.task[ifv_1_0['obj_id']] = ['maneuver', 6047]
                    if ifv_1_0['cur_hex'] == 6047:
                        factionAI.task[ifv_1_0['obj_id']] = ['maneuver', 5549]
                    if ifv_1_0['cur_hex'] == 5549:
                        factionAI.task[ifv_1_0['obj_id']] = ['maneuver', 4846]
                    if ifv_1_0['cur_hex'] == 4846 and infantry_1_0['on_board'] == 1:
                        factionAI.task[ifv_1_0['obj_id']] = ['deliver_safe', infantry_1_0['obj_id'], 4846]
                    if ifv_1_0['cur_hex'] == 4846 and infantry_1_0['get_off_remain_time'] > 0:
                        factionAI.task[ifv_1_0['obj_id']] = ['maneuver', 5448]
                if ifv_1_0['cur_hex'] == 5448 and not ifv_1_0['passenger_ids']:
                    factionAI.task[ifv_1_0['obj_id']] = ['guard2nd', True]
            if ifv_1_1:
                infantry_1_1 = myAgent.get_bop(BlueOprs.XianQianDui_1.Infantry_1)
                if infantry_1_1:
                    if ifv_1_1['cur_hex'] == 6438 and infantry_1_1['on_board'] == 0 and infantry_1_1['get_on_remain_time'] <= 0:
                        factionAI.task[ifv_1_1['obj_id']] = ['load', infantry_1_1['obj_id']]
                    if ifv_1_1['cur_hex'] == 6438 and infantry_1_1['get_on_remain_time'] > 0:
                        factionAI.task[ifv_1_1['obj_id']] = ['maneuver', 6344]
                    if ifv_1_1['cur_hex'] == 6344:
                        factionAI.task[ifv_1_1['obj_id']] = ['maneuver', 6047]
                    if ifv_1_1['cur_hex'] == 6047:
                        factionAI.task[ifv_1_1['obj_id']] = ['maneuver', 5549]
                    if ifv_1_1['cur_hex'] == 5549:
                        factionAI.task[ifv_1_1['obj_id']] = ['maneuver', 4849]
                    if ifv_1_1['cur_hex'] == 4849 and infantry_1_1['on_board'] == 1:
                        factionAI.task[ifv_1_1['obj_id']] = ['deliver_safe', infantry_1_1['obj_id'], 4849]
                    if ifv_1_1['cur_hex'] == 4849 and infantry_1_1['get_off_remain_time'] > 0:
                        factionAI.task[ifv_1_1['obj_id']] = ['maneuver', 5450]
                if ifv_1_1['cur_hex'] == 5450 and not ifv_1_1['passenger_ids']:
                    factionAI.task[ifv_1_1['obj_id']] = ['guard2nd', True]
            if ifv_2_0:
                infantry_2_0 = myAgent.get_bop(BlueOprs.XianQianDui_2.Infantry_0)
                if infantry_2_0:
                    if ifv_2_0['cur_hex'] == 6546 and infantry_2_0['on_board'] == 0 and infantry_2_0['get_on_remain_time'] <= 0:
                        factionAI.task[ifv_2_0['obj_id']] = ['load', infantry_2_0['obj_id']]
                    if ifv_2_0['cur_hex'] == 6546 and infantry_2_0['get_on_remain_time'] > 0:
                        factionAI.task[ifv_2_0['obj_id']] = ['maneuver', 6047]
                    if ifv_2_0['cur_hex'] == 6047:
                        factionAI.task[ifv_2_0['obj_id']] = ['maneuver', 5748]
                    if ifv_2_0['cur_hex'] == 5748:
                        factionAI.task[ifv_2_0['obj_id']] = ['maneuver', 5247]
                    if ifv_2_0['cur_hex'] == 5247:
                        factionAI.task[ifv_2_0['obj_id']] = ['maneuver', 5046]
                    if ifv_2_0['cur_hex'] == 5046 and infantry_2_0['on_board'] == 1:
                        factionAI.task[ifv_2_0['obj_id']] = ['deliver_safe', infantry_2_0['obj_id'], 5046]
                    if ifv_2_0['cur_hex'] == 5046 and infantry_2_0['get_off_remain_time'] > 0:
                        factionAI.task[ifv_2_0['obj_id']] = ['maneuver', 5548]
                if ifv_2_0['cur_hex'] == 5548 and not ifv_2_0['passenger_ids']:
                    factionAI.task[ifv_2_0['obj_id']] = ['guard2nd', True]
            if ifv_2_1:
                infantry_2_1 = myAgent.get_bop(BlueOprs.XianQianDui_2.Infantry_1)
                if infantry_2_1:
                    if ifv_2_1['cur_hex'] == 6647 and infantry_2_1['on_board'] == 0 and infantry_2_1['get_on_remain_time'] <= 0:
                        factionAI.task[ifv_2_1['obj_id']] = ['load', infantry_2_1['obj_id']]
                    if ifv_2_1['cur_hex'] == 6647 and infantry_2_1['get_on_remain_time'] > 0:
                        factionAI.task[ifv_2_1['obj_id']] = ['maneuver', 6047]
                    if ifv_2_1['cur_hex'] == 6047:
                        factionAI.task[ifv_2_1['obj_id']] = ['maneuver', 4948]
                    if ifv_2_1['cur_hex'] == 4948 and infantry_2_1['on_board'] == 1:
                        factionAI.task[ifv_2_1['obj_id']] = ['deliver_safe', infantry_2_1['obj_id'], 4948]
                    if ifv_2_1['cur_hex'] == 4948 and infantry_2_1['get_off_remain_time'] > 0:
                        factionAI.task[ifv_2_1['obj_id']] = ['maneuver', 5449]
                if ifv_2_1['cur_hex'] == 5449 and not ifv_2_1['passenger_ids']:
                    factionAI.task[ifv_2_1['obj_id']] = ['guard2nd', True]
            if ifv_3_0:
                if ifv_3_0['cur_hex'] == 5551:
                    factionAI.task[ifv_3_0['obj_id']] = ['maneuver', 5650]
                if ifv_3_0['cur_hex'] == 5650:
                    factionAI.task[ifv_3_0['obj_id']] = ['guard2nd', True]
            if ifv_3_1:
                if ifv_3_1['cur_hex'] == 5652:
                    factionAI.task[ifv_3_1['obj_id']] = ['maneuver', 5749]
                if ifv_3_1['cur_hex'] == 5749:
                    factionAI.task[ifv_3_1['obj_id']] = ['guard2nd', True]
            if ifv_4_0:
                if ifv_4_0['cur_hex'] == 5555:
                    factionAI.task[ifv_4_0['obj_id']] = ['maneuver', 5549]
                if ifv_4_0['cur_hex'] == 5549:
                    factionAI.task[ifv_4_0['obj_id']] = ['guard2nd', True]
            if ifv_4_1:
                infantry_4_1 = myAgent.get_bop(BlueOprs.XianQianDui_4.Infantry_1)
                if infantry_4_1:
                    if ifv_4_1['cur_hex'] == 5656 and infantry_4_1['on_board'] == 0 and infantry_4_1['get_on_remain_time'] <= 0:
                        factionAI.task[ifv_4_1['obj_id']] = ['load', infantry_4_1['obj_id']]
                    if ifv_4_1['cur_hex'] == 5656 and infantry_4_1['get_on_remain_time'] > 0:
                        factionAI.task[ifv_4_1['obj_id']] = ['maneuver', 5152]
                    if ifv_4_1['cur_hex'] == 5152 and infantry_4_1['on_board'] == 1:
                        factionAI.task[ifv_4_1['obj_id']] = ['deliver_safe', infantry_4_1['obj_id'], 5152]
                    if ifv_4_1['cur_hex'] == 5152 and infantry_4_1['get_off_remain_time'] > 0:
                        factionAI.task[ifv_4_1['obj_id']] = ['maneuver', 5550]
                if ifv_4_1['cur_hex'] == 5550 and not ifv_4_1['passenger_ids']:
                    factionAI.task[ifv_4_1['obj_id']] = ['guard2nd', True]
        elif 'Gather' in self.group_task:
            if self.group_task[1] == 0:
                support_opr = []
                remain_ifvs = {}
                carry_ifv = -1
                infantry_3_1 = myAgent.get_bop(BlueOprs.XianQianDui_3.Infantry_1)
                if infantry_3_1:
                    carry_ifv = min(self.members, key=lambda ifv_id: cal_distance(infantry_3_1['cur_hex'],
                                                                                  myAgent.get_bop(ifv_id)['cur_hex']))
                    factionAI.task[carry_ifv] = ['deliver', infantry_3_1['obj_id'], 4441]
                first_ifv_id, second_ifv_id = None, None
                first_dist, second_dist = 1000, 1000
                for ifv_id in self.members:
                    ifv = myAgent.get_bop(ifv_id)
                    if not ifv:
                        continue
                    cur_dist = cal_distance(5044, ifv['cur_hex'])
                    if cur_dist < first_dist:
                        first_dist = cur_dist
                        first_ifv_id = ifv_id
                        continue
                    if cur_dist < second_dist:
                        second_dist = cur_dist
                        second_ifv_id = ifv_id
                if isinstance(first_ifv_id, int):
                    support_opr.append(first_ifv_id)
                    first_ifv = myAgent.get_bop(first_ifv_id)
                    if first_ifv:
                        factionAI.task[first_ifv_id] = ['ambush4th', 4736, True]
                if isinstance(second_ifv_id, int):
                    support_opr.append(second_ifv_id)
                    second_ifv = myAgent.get_bop(second_ifv_id)
                    if second_ifv:
                        factionAI.task[second_ifv_id] = ['ambush4th', 4838, True]
                tar_locs = list(range(4343, 4347))
                for ifv_id in self.members:
                    if ifv_id in support_opr:
                        continue
                    if ifv_id == carry_ifv:
                        continue
                    ifv = myAgent.get_bop(ifv_id)
                    if not ifv:
                        continue
                    tar_loc = random.choice(tar_locs)
                    remain_ifvs[ifv_id] = tar_loc
                    factionAI.task[ifv_id] = ['ambush4th', tar_loc, False]
                self.group_task.append(support_opr)
                self.group_task.append(remain_ifvs)
                self.group_task.append(carry_ifv)
                self.group_task[1] = 1
            elif self.group_task[1] == 1:
                support_opr = self.group_task[2]
                if support_opr:
                    for m in range(len(support_opr)):
                        if not myAgent.get_bop(support_opr[m]):
                            continue
                        if m == 0:
                            factionAI.task[support_opr[m]] = ['ambush4th', 4736, True]
                        if m == 1:
                            factionAI.task[support_opr[m]] = ['ambush4th', 4838, True]
                remain_ifvs = self.group_task[3]
                for ifv_id, tar_loc in remain_ifvs.items():
                    if not myAgent.get_bop(ifv_id):
                        continue
                    factionAI.task[ifv_id] = ['ambush4th', tar_loc, False]
                carry_ifv = self.group_task[4]
                if myAgent.get_bop(carry_ifv):
                    infantry_3_1 = myAgent.get_bop(BlueOprs.XianQianDui_3.Infantry_1)
                    if infantry_3_1:
                        factionAI.task[carry_ifv] = ['deliver', infantry_3_1['obj_id'], 4540]


class BuBing:
    """步兵组的策略实现"""

    def __init__(self, factionAI):
        self.members = factionAI.group_static['bu_bing']
        self.group_task = ['Deployment']
        self.tactic = None
        self.cur_step = 0

    def plan(self, factionAI, myAgent):
        self.cur_step = myAgent.observation['time']['cur_step']
        self.members = factionAI.group_info['bu_bing']['obj_ids']
        if not self.members:
            return

        # === 更新组任务 ===
        self.update_group_task(factionAI, myAgent)

        # === 分派算子任务 ===
        self.assign_opr_tasks(factionAI, myAgent)

    def update_group_task(self, factionAI, myAgent):
        pass

    def assign_opr_tasks(self, factionAI, myAgent):
        infantry_1_0 = myAgent.get_bop(BlueOprs.XianQianDui_1.Infantry_0)
        infantry_1_1 = myAgent.get_bop(BlueOprs.XianQianDui_1.Infantry_1)
        infantry_2_0 = myAgent.get_bop(BlueOprs.XianQianDui_2.Infantry_0)
        infantry_2_1 = myAgent.get_bop(BlueOprs.XianQianDui_2.Infantry_1)
        infantry_3_0 = myAgent.get_bop(BlueOprs.XianQianDui_3.Infantry_0)
        infantry_3_1 = myAgent.get_bop(BlueOprs.XianQianDui_3.Infantry_1)
        infantry_4_0 = myAgent.get_bop(BlueOprs.XianQianDui_4.Infantry_0)
        infantry_4_1 = myAgent.get_bop(BlueOprs.XianQianDui_4.Infantry_1)

        if 'Deployment' in self.group_task:
            """=== 部署任务 ==="""
            if infantry_1_0:
                if infantry_1_0['get_off_remain_time'] > 0:
                    factionAI.task[infantry_1_0['obj_id']] = ['maneuver', 4243]
                if infantry_1_0['cur_hex'] == 4243:
                    factionAI.task[infantry_1_0['obj_id']] = ['guard2nd', True]
            if infantry_1_1:
                if infantry_1_1['get_off_remain_time'] > 0:
                    factionAI.task[infantry_1_1['obj_id']] = ['maneuver', 4146]
                if infantry_1_1['cur_hex'] == 4146:
                    factionAI.task[infantry_1_1['obj_id']] = ['guard2nd', True]
            if infantry_2_0:
                if infantry_2_0['get_off_remain_time'] > 0:
                    factionAI.task[infantry_2_0['obj_id']] = ['maneuver', 3845]
                if infantry_2_0['cur_hex'] == 3845:
                    factionAI.task[infantry_2_0['obj_id']] = ['guard2nd', True]
            if infantry_2_1:
                if infantry_2_1['get_off_remain_time'] > 0:
                    factionAI.task[infantry_2_1['obj_id']] = ['maneuver', 4245]
                if infantry_2_1['cur_hex'] == 4245:
                    factionAI.task[infantry_2_1['obj_id']] = ['guard2nd', True]
            if infantry_3_0:
                if infantry_3_0['cur_hex'] == 5551:
                    factionAI.task[infantry_3_0['obj_id']] = ['maneuver', 4345]
                if infantry_3_0['cur_hex'] == 4345 and self.cur_step <= 1550:
                    factionAI.task[infantry_3_0['obj_id']] = ['guard2nd', True]
                if infantry_3_0['cur_hex'] == 4345 and self.cur_step > 1550:
                    factionAI.task[infantry_3_0['obj_id']] = ['maneuver', 3943]
                if infantry_3_0['cur_hex'] == 3943:
                    factionAI.task[infantry_3_0['obj_id']] = ['guard2nd', True]
            if infantry_3_1:
                if infantry_3_1['cur_hex'] == 5652:
                    factionAI.task[infantry_3_1['obj_id']] = ['maneuver', 5649]
                if infantry_3_1['cur_hex'] == 5649:
                    factionAI.task[infantry_3_1['obj_id']] = ['guard2nd', True]
            if infantry_4_0:
                if infantry_4_0['cur_hex'] == 5555:
                    factionAI.task[infantry_4_0['obj_id']] = ['maneuver', 3947]
                if infantry_4_0['cur_hex'] == 3947:
                    factionAI.task[infantry_4_0['obj_id']] = ['guard2nd', True]
            if infantry_4_1:
                if infantry_4_1['get_off_remain_time'] > 0:
                    factionAI.task[infantry_4_1['obj_id']] = ['maneuver', 4047]
                if infantry_4_1['cur_hex'] == 4047:
                    factionAI.task[infantry_4_1['obj_id']] = ['guard2nd', True]


class PaoBing:
    """炮兵组的策略实现"""

    def __init__(self, factionAI):
        self.members = factionAI.group_static['pao_bing']
        self.group_task = []
        self.tactic = None
        self.cur_step = 0

    def plan(self, factionAI, myAgent):
        self.cur_step = myAgent.observation['time']['cur_step']
        self.members = factionAI.group_info['pao_bing']['obj_ids']
        if not self.members:
            return

        # === 更新组任务 ===
        self.update_group_task(factionAI, myAgent)

        # === 分派算子任务 ===
        self.assign_opr_tasks(factionAI, myAgent)

    def update_group_task(self, factionAI, myAgent):
        """炮兵组任务"""
        """=== 清空炮兵组任务 ==="""
        # 清空条件：间瞄火力快要到达时
        flag_clean = False
        for jm_info in myAgent.observation['jm_points']:
            if jm_info['obj_id'] in self.members:
                if 100 < jm_info['fly_time'] < 150:
                    flag_clean = True
                    break
        if flag_clean:
            if self.group_task:
                if self.group_task[2]:
                    directing_opr_id = self.group_task[2]
                    if 'direct_artilleries' in factionAI.task.get(directing_opr_id, []):
                        factionAI.task.pop(directing_opr_id)
            self.group_task = []

        """=== 删除死亡的校射算子 ==="""
        if self.group_task:
            if isinstance(self.group_task[2], int):
                directing_opr_id = self.group_task[2]
                if not myAgent.get_bop(directing_opr_id):
                    self.group_task[2] = None

        """=== 关键点位压制任务 ==="""
        if self.new_plan_check(myAgent):
            if self.cur_step <= 150:
                self.group_task = ['FireSupport', 2547, None]  # 第1波压制
                return

        """=== 常规任务 ==="""
        if self.cur_step <= 150:
            return
        if not self.new_plan_check(myAgent):
            return
        # --- 计算飞行时间 ---
        fly_time = 0
        for jm_info in myAgent.observation['jm_points']:
            if jm_info['obj_id'] in self.members:
                if jm_info['fly_time'] > fly_time:
                    fly_time = jm_info['fly_time']
        if fly_time > 100:  # 快要达到的火力不打断
            return
        # --- 确定炮兵目标 ---
        being_jm_hexes = []  # 正在被间瞄损伤的六角格
        for jm_info in myAgent.observation['jm_points']:
            if jm_info['status'] == 0:  # 正在飞行
                being_jm_hexes.append(jm_info['pos'])
            elif jm_info['status'] == 1 and jm_info['boom_time'] < 150:
                being_jm_hexes.append(jm_info['pos'])
        being_jm_hexes = list(set(being_jm_hexes))
        being_planed_hexes = []  # 在计划中的间瞄目标
        if self.group_task:
            being_planed_hexes.append(self.group_task[1])
        near_by_hexes = []  # 我方算子所在格
        for opr in myAgent.get_our_oprs():
            if opr['type'] != BopType.Aircraft:
                opr_loc = opr['cur_hex']
                near_by_hexes.append(opr_loc)
        near_by_hexes = list(set(near_by_hexes))
        targets = self.get_artillery_target(myAgent)
        for key, value in targets.items():  # 过滤正在遭受打击的目标，以及列入间瞄任务的目标
            if not value:
                for tar_id in value:
                    tar_loc = myAgent.get_bop(tar_id)['cur_hex']
                    if tar_loc in being_jm_hexes + being_planed_hexes + near_by_hexes:
                        targets[key].remove(tar_id)
        # --- 有受压制的步兵时，优先打击此类目标 ---
        if targets[0]:
            target = targets[0][0]
            if self.group_task:
                cur_tar_loc = self.group_task[1]
                if check_keep_infantry_in_hex(cur_tar_loc, myAgent.situations.enemies):  # 当前的打击目标就是压制步兵
                    return
            tar_loc = myAgent.get_enemy(target)['cur_hex']
            self.group_task = ['FireSupport', tar_loc, None]
        elif not self.group_task:
            # === 没有受压制的步兵时，根据空闲的炮兵组，按照优先顺序分派jm任务 ===
            # 筛选炮击目标六角格
            candidate_targets = None
            flag_moving_infantry = False  # 选中的目标是否是机动中的步兵
            for m in range(1, 4):
                if targets[m]:
                    candidate_targets = targets[m]
                    if m == 3:
                        flag_moving_infantry = True
                    break
            if candidate_targets:
                arti_locs = []
                for arti_id in self.members:
                    arti = myAgent.get_bop(arti_id)
                    if arti:
                        arti_locs.append(arti['cur_hex'])
                # 视线中的目标格优先
                candidate_locs = [myAgent.get_enemy_info(obj_id)['operator']['cur_hex'] for obj_id in
                                  candidate_targets]
                candidate_locs = list(set(candidate_locs))
                candidate_locs_first, candidate_locs_others = [], []
                for hex in candidate_locs:  # 判断是否在视线中
                    for opr in myAgent.get_our_oprs():
                        if opr['sub_type'] in [BopType.Helicopter, BopType.CruiseMissile, BopType.Artillery]:
                            continue
                        opr_loc = opr['cur_hex']
                        opr_type = opr['type']
                        if opr_type == BopType.Aircraft:
                            sight_dist = 2
                            if myAgent.map.can_see(opr_loc, hex, 2) and cal_distance(opr_loc, hex) <= sight_dist:
                                candidate_locs_first.append(hex)
                                break
                        else:
                            sight_dist = 25
                            if myAgent.map.can_see(opr_loc, hex, 0) and cal_distance(opr_loc, hex) <= sight_dist:
                                candidate_locs_first.append(hex)
                                break
                candidate_locs_first = list(set(candidate_locs_first))
                candidate_locs_others = list(set(candidate_locs).difference(set(candidate_locs_first)))
                # 按照距离筛选同类目标
                if candidate_locs_first:
                    tar_loc = get_min_dist_loc(candidate_locs_first, arti_locs, myAgent)
                else:
                    tar_loc = get_min_dist_loc(candidate_locs_others, arti_locs, myAgent)
                # 对于机动中的步兵目标，做目标格预测
                if flag_moving_infantry:
                    nearest_city = min(myAgent.observation['cities'], key=lambda x: cal_distance(tar_loc, x['coord']))
                    tar_loc_predict = get_line(tar_loc, nearest_city['coord'])[0]
                    flag_opr_in_hex = False
                    for opr in myAgent.get_our_oprs():
                        if opr['type'] == BopType.Aircraft:
                            continue
                        if opr['cur_hex'] == tar_loc_predict:  # 保证不会误伤友军
                            flag_opr_in_hex = True
                    if not flag_opr_in_hex:
                        tar_loc = tar_loc_predict
                self.group_task = ['FireSupport', tar_loc, None]
            else:  # 无目标可选，不分派任务
                self.group_task = []

        """=== 为炮兵组任务分配校射算子 ==="""
        if self.cur_step > 150:
            if not self.group_task:
                return
            if isinstance(self.group_task[2], int):
                return
            fly_time = 0
            for jm_info in myAgent.observation['jm_points']:
                if jm_info['obj_id'] in self.members:
                    if jm_info['fly_time'] > fly_time:
                        fly_time = jm_info['fly_time']
            if fly_time > 50:  # 只为早期任务分配校射算子
                return
            # 筛选校射算子
            tar_loc = self.group_task[1]
            directing_opr_id = self.get_directing_opr(tar_loc, myAgent)
            if directing_opr_id:
                self.group_task[2] = directing_opr_id  # 完善炮兵组任务
                group_name = get_group_by_obj_id(directing_opr_id, factionAI)
                if group_name:
                    factionAI.group_info[group_name]['obj_ids'].remove(directing_opr_id)  # 暂时将校射算子调离原分组
                    if 'direct_artilleries' not in factionAI.task.get(directing_opr_id, []) \
                            and factionAI.task.get(directing_opr_id) \
                            and not factionAI.task_backup.get(directing_opr_id):
                        factionAI.task_backup[directing_opr_id] = factionAI.task.pop(directing_opr_id)

    def assign_opr_tasks(self, factionAI, myAgent):
        """为算子分派任务"""
        """=== 清除完成的校射任务 ==="""
        if self.group_task:
            if isinstance(self.group_task[2], int):
                directing_opr_ids = [self.group_task[2]]
            else:
                directing_opr_ids = []
            for opr in myAgent.get_our_oprs():
                obj_id = opr['obj_id']
                if obj_id not in factionAI.task.keys():
                    continue
                if 'direct_artilleries' in factionAI.task[obj_id]:
                    if not directing_opr_ids:
                        factionAI.task.pop(obj_id)
                    else:
                        if obj_id not in directing_opr_ids:
                            factionAI.task.pop(obj_id)

        """=== 分派炮兵齐射任务 ==="""
        if self.group_task:
            for arti_id in self.members:
                factionAI.task[arti_id] = ['jm_salvo', self.group_task[1]]

        """=== 分派校射任务 ==="""
        if self.group_task:
            if isinstance(self.group_task[2], int):
                directing_opr_id = self.group_task[2]
                if directing_opr_id in factionAI.task.keys():
                    if factionAI.task[directing_opr_id] == ['direct_artilleries', self.group_task[1]]:
                        return
                factionAI.task[directing_opr_id] = ['direct_artilleries', self.group_task[1]]

    def get_directing_opr(self, tar_loc, myAgent):
        """为炮兵组选择校射算子"""
        # === 确定对tar_enemies的可视半径 ===
        observe_radius = {}  # 最小可观察范围
        observe_radius[BopType.Infantry] = 25
        observe_radius[BopType.Vehicle] = 25
        observe_radius[BopType.Drone] = 2
        # === 计算对tar_enemies的最小观察区域 ===
        dist_matrix = myAgent.my_map['dist_matrix']
        map_size = myAgent.get_map_size()
        n_hexes = map_size['row'] * map_size['col']
        tar_loc_ind = mapid_2_matind(tar_loc, myAgent.get_map_size())
        dist_vec = dist_matrix[tar_loc_ind]
        see_vec_ground = myAgent.my_map['see_matrix'][0][tar_loc_ind]
        see_vec_air = myAgent.my_map['see_matrix'][2][:, tar_loc_ind]
        observe_area = {}
        for bop_type, radius in observe_radius.items():
            if bop_type in [BopType.Infantry, BopType.Vehicle]:
                observe_area[bop_type] = np.arange(n_hexes)[dist_vec <= observe_radius[bop_type] & see_vec_ground]
            else:
                observe_area[bop_type] = np.arange(n_hexes)[dist_vec <= observe_radius[bop_type] & see_vec_air]
        # === 筛选出能够在150s内抵达最小观察区域的我方算子 ===
        cost_matrix_infantry = myAgent.my_map['cost_matrix'][1]
        cost_matrix_little_aircraft = dist_matrix * 7.2
        candidate_drones, candidate_infantries, min_costs_drones, min_costs_infantries = [], [], {}, {}
        for opr in myAgent.get_our_oprs():
            if opr['sub_type'] in [BopType.Artillery, BopType.CruiseMissile, BopType.Helicopter]:
                continue
            opr_loc_ind = mapid_2_matind(opr['cur_hex'], map_size)
            if opr['type'] == BopType.Infantry:
                cost_vec = cost_matrix_infantry[opr_loc_ind]
                min_cost_infantry = np.min(cost_vec[observe_area[BopType.Infantry]])
                if min_cost_infantry < 150:
                    candidate_infantries.append(opr)
                    min_costs_infantries[opr['obj_id']] = min_cost_infantry
            elif opr['sub_type'] == BopType.Drone:
                cost_vec = cost_matrix_little_aircraft[opr_loc_ind]
                min_cost_drone = np.min(cost_vec[observe_area[BopType.Drone]])
                if min_cost_drone < 150:
                    candidate_drones.append(opr)
                    min_costs_drones[opr['obj_id']] = min_cost_drone
        # 进一步从candidate_oprs筛选出最优的校射算子
        if not candidate_drones and not candidate_infantries:
            return None
        tar_enemies = []
        for enemy_info in myAgent.situations.enemies:
            if enemy_info['spread_flag']:
                enemy = enemy_info['operator']
                ene_loc = enemy['cur_hex']
                if enemy['type'] != BopType.Aircraft:
                    if enemy['armor'] != ArmorType.Composit:
                        if ene_loc == tar_loc:
                            if np.max(enemy_info['pos_probs']) > 1 - 1e-8:
                                tar_enemies.append(enemy)
        if not tar_enemies:
            return None
        if candidate_drones:
            best_opr = min(candidate_drones, key=lambda opr: min_costs_drones[opr['obj_id']])
            best_opr_id = best_opr['obj_id']
            return best_opr_id
        elif candidate_infantries:
            best_opr = min(candidate_infantries, key=lambda opr: min_costs_infantries[opr['obj_id']])
            best_opr_id = best_opr['obj_id']
            return best_opr_id

    def new_plan_check(self, myAgent):
        for anti_id in self.members:
            if myAgent.observation['valid_actions'].get(anti_id):
                if not myAgent.observation['valid_actions'][anti_id].get(ActionType.JMPlan):
                    return False
        return True

    def get_artillery_target(self, myAgent):
        """确定炮兵的目标"""
        targets = {0: [], 1: [], 2: [], 3: []}  # 按级别区分的目标
        # 0：压制的步兵
        # 1：停止状态的战车（周围没有步兵）
        # 2：夺控点旁边的敌方单位
        # 3: 机动中的步兵
        # 区分目标等级
        for enemy_info in myAgent.situations.enemies:
            if not enemy_info['spread_flag']:
                continue
            enemy = enemy_info['operator']
            ene_id = enemy['obj_id']
            ene_loc = enemy['cur_hex']
            if enemy['type'] == BopType.Aircraft:
                continue
            if enemy['armor'] == ArmorType.Composit:
                continue
            if np.max(enemy_info['pos_probs']) < 1 - 1e-8:
                continue
            if enemy['type'] == BopType.Infantry and enemy['keep'] == 1:
                targets[0].append(ene_id)  # 最高等级是压制的步兵
            elif enemy['sub_type'] == BopType.IFV and enemy['stop'] == 1:
                flag_infantry = False
                for e_info in myAgent.situations.enemies:
                    if not e_info['spread_flag']:
                        continue
                    e = e_info['operator']
                    if e['type'] != BopType.Infantry:
                        continue
                    if cal_distance(e['cur_hex'], enemy['cur_hex']) <= 1:
                        flag_infantry = True
                if not flag_infantry:
                    targets[1].append(ene_id)  # 其次是停止状态的战车
            elif min([cal_distance(ene_loc, city['coord']) for city in myAgent.observation['cities']]) <= 1:
                targets[2].append(ene_id)  # 第三是夺控点周边的算子（非坦克）
            elif enemy['type'] == BopType.Infantry and enemy['speed'] > 0:
                targets[3].append(ene_id)
        return targets


class ZhiShengJi:
    """直升机组的策略实现"""

    def __init__(self, factionAI):
        self.members = factionAI.group_static['zhi_sheng_ji']
        self.group_task = ['Deployment']
        self.tactic = []
        self.cur_step = 0

    def plan(self, factionAI, myAgent):
        self.cur_step = myAgent.observation['time']['cur_step']
        self.members = factionAI.group_info['zhi_sheng_ji']['obj_ids']
        if not self.members:
            return

        # === 更新组任务 ===
        self.update_group_task(factionAI, myAgent)

        # === 分派算子任务 ===
        self.assign_opr_tasks(factionAI, myAgent)

    def update_group_task(self, factionAI, myAgent):
        # --- 部署任务 ---
        pass

    def assign_opr_tasks(self, factionAI, myAgent):
        heli_0 = myAgent.get_bop(BlueOprs.ZhiShengJi.Helicopter_0)
        heli_1 = myAgent.get_bop(BlueOprs.ZhiShengJi.Helicopter_1)
        if 'Deployment' in self.group_task:
            if heli_0:
                if heli_0['cur_hex'] == 7337:
                    factionAI.task[heli_0['obj_id']] = ['ambush', 3838]  # +++
                if self.cur_step >= 380:
                    factionAI.task[heli_0['obj_id']] = ['fire_propulsion']  # +++
            if heli_1:
                if heli_1['cur_hex'] == 7637:
                    factionAI.task[heli_1['obj_id']] = ['ambush', 3228]  # +++
                if self.cur_step >= 330:
                    factionAI.task[heli_1['obj_id']] = ['fire_propulsion']  # +++
            # 弹药耗尽后的处理
            if heli_0:
                if sum(heli_0['remain_bullet_nums'].values()) <= 0:
                    factionAI.task[heli_0['obj_id']] = ['rapid_march', 7435, 2]  # +++
            if heli_1:
                if sum(heli_1['remain_bullet_nums'].values()) <= 0:
                    factionAI.task[heli_1['obj_id']] = ['rapid_march', 7436, 2]  # +++


class WuRenJi:
    """无人机组的策略实现"""

    def __init__(self, factionAI):
        self.members = factionAI.group_static['wu_ren_ji']
        self.group_task = ['Deployment']
        self.tactic = []
        self.cur_step = 0

    def plan(self, factionAI, myAgent):
        self.cur_step = myAgent.observation['time']['cur_step']
        self.members = factionAI.group_info['wu_ren_ji']['obj_ids']
        if not self.members:
            return

        # === 更新组任务 ===
        self.update_group_task(factionAI, myAgent)

        # === 分派算子任务 ===
        self.assign_opr_tasks(factionAI, myAgent)

    def update_group_task(self, factionAI, myAgent):
        if 'Deployment' in self.group_task:
            flag_change_task = True
            for drone_id in self.members:
                drone = myAgent.get_bop(drone_id)
                if drone:
                    if 'drone_scout' not in factionAI.task.get(drone['obj_id'], []):
                        flag_change_task = False
            if flag_change_task:
                self.group_task = ['Scout']

    def assign_opr_tasks(self, factionAI, myAgent):
        if 'Deployment' in self.group_task:
            drone_0 = myAgent.get_bop(BlueOprs.WuRenJi.Drone_0)
            drone_1 = myAgent.get_bop(BlueOprs.WuRenJi.Drone_1)
            if drone_0:
                if drone_0['cur_hex'] == 7338:
                    factionAI.task[drone_0['obj_id']] = ['maneuver', 2847]  # +++
                if drone_0['cur_hex'] == 2847:
                    factionAI.task[drone_0['obj_id']] = ['drone_scout']  # +++
                if drone_1['cur_hex'] == 7638:
                    factionAI.task[drone_1['obj_id']] = ['maneuver', 2644]  # +++
                if drone_1['cur_hex'] == 2644:
                    factionAI.task[drone_1['obj_id']] = ['drone_scout']  # +++
        elif 'Scout' in self.group_task:
            for drone_id in self.members:
                drone = myAgent.get_bop(drone_id)
                if drone:
                    factionAI.task[drone['obj_id']] = ['drone_scout']  # +++


def check_keep_infantry_in_hex(loc, enemies_info):
    """判断六角格loc中是否有压制状态的步兵，用于炮兵目标选择"""
    for enemy_info in enemies_info:
        if enemy_info['spread_flag']:
            enemy = enemy_info['operator']
            if enemy['cur_hex'] == loc:
                if enemy['keep'] == 1:
                    if enemy['type'] == BopType.Infantry:
                        return True
    return False


def get_min_dist_loc(candidate_locs, refer_locs, myAgent):
    """根据距离refer_locs远近从candidate_locs中筛选六角格"""
    map_size = myAgent.get_map_size()
    candidate_locs_ind = mapid_2_matind(np.array(candidate_locs), map_size)
    refer_locs_ind = mapid_2_matind(np.array(refer_locs), map_size)
    dist_matrix = myAgent.my_map['dist_matrix'][candidate_locs_ind.reshape(-1, 1), refer_locs_ind.reshape(1, -1)]
    avg_dist_vec = np.mean(dist_matrix, axis=1)
    best_ind = np.argmin(avg_dist_vec)
    return candidate_locs[best_ind]


def get_group_by_obj_id(obj_id, factionAI):
    for group_name, info in factionAI.group_info.items():
        if obj_id in info['obj_ids']:
            return group_name
    return None


def get_init_group_by_obj_id(obj_id, factionAI):
    for group_name, info in factionAI.group_static.items():
        if obj_id in info:
            return group_name
    return None

